﻿using System;
using System.Text;

namespace msilgc.cbuilder.CSyntaxTree
{
    public interface IVariable
    {
        bool IsPointer { get; set; }
        string Name { get; set; }
        bool OutVariable { get; set; }
        Type Type { get; set; }
        string TypeString { get; }
        string ArrayBaseType { get; }
        bool IsPrimitive { get; }
        string ToString();
        void EmitDeclaration(StringBuilder builder);
        void Emit(StringBuilder builder);
        IVariable CloneWithPrefix(string namePrefix);
    }

    internal class Variable : IVariable
    {
        public string Name { get; set; }
        public Type Type { get; set; }
        public bool OutVariable { get; set; }
        public bool IsPointer { get; set; }

        public Variable(IVariable var1, string namePrefix)
        {
            Type = var1.Type;
            Name = namePrefix + var1.Name;
            IsPointer = false;
            OutVariable = false;
        }

        public Variable(string name, Type type) {
            Type = type;
            Name = name;
            OutVariable = false;
            IsPointer = false;
        }

        public IVariable CloneWithPrefix(string namePrefix)
        {
            return new Variable(this, namePrefix);
        }

        public override string ToString() {
            return Name + ":" + Type;
        }

        public string TypeString
        {
            get { return GetTypeString(Type); }
        }

        public string ArrayBaseType
        {
            get
            {
                string typeName;
                if (Type == typeof(int[]) || Type == typeof(Int32[])) {
                    typeName = "int";
                } else if (Type == typeof(uint[]) || Type == typeof(UInt32[])) {
                    typeName = "unsigned int";
                } else if (Type == typeof(short[]) || Type == typeof(Int16[])) {
                    typeName = "short";
                } else if (Type == typeof(ushort[]) || Type == typeof(UInt16[])) {
                    typeName = "unsigned short";
                } else if (Type == typeof(long[]) || Type == typeof(Int64[])) {
                    typeName = "long int";
                } else if (Type == typeof(ulong[]) || Type == typeof(UInt64[])) {
                    typeName = "unsigned long int";
                } else if (Type == typeof(float[]) || Type == typeof(Single[])) {
                    typeName = "float";
                } else if (Type == typeof(double[]) || Type == typeof(Double[])) {
                    typeName = "double";
                } else if (Type == typeof(char[]) || Type == typeof(Char[]) || Type == typeof(byte[]) || Type == typeof(Byte[])) {
                    typeName = "char";
                } else {
                    throw new Exception("type is not an array: " + Type.Name);
                }
                return typeName;
            }
        }

        public bool IsPrimitive
        {
            get { return _IsPrimitive(Type); }
        }

        private static bool _IsPrimitive(Type type)
        {
            if (type == typeof(int) || type == typeof(Int32)) {
                return true;
            } else if (type == typeof(uint) || type == typeof(UInt32)) {
                return true;
            } else if (type == typeof(short) || type == typeof(Int16)) {
                return true;
            } else if (type == typeof(ushort) || type == typeof(UInt16)) {
                return true;
            } else if (type == typeof(long) || type == typeof(Int64)) {
                return true;
            } else if (type == typeof(ulong) || type == typeof(UInt64)) {
                return true;
            } else if (type == typeof(float) || type == typeof(Single)) {
                return true;
            } else if (type == typeof(double) || type == typeof(Double)) {
                return true;
            } else if (type == typeof(char) || type == typeof(Char)) {
                return true;
            } else if (type == typeof(byte) || type == typeof(Byte)) {
                return true;
            } else if (type == typeof(int[]) || type == typeof(Int32[])) {
                return false;
            } else if (type == typeof(uint[]) || type == typeof(UInt32[])) {
                return false;
            } else if (type == typeof(short[]) || type == typeof(Int16[])) {
                return false;
            } else if (type == typeof(ushort[]) || type == typeof(UInt16[])) {
                return false;
            } else if (type == typeof(long[]) || type == typeof(Int64[])) {
                return false;
            } else if (type == typeof(ulong[]) || type == typeof(UInt64[])) {
                return false;
            } else if (type == typeof(float[]) || type == typeof(Single[])) {
                return false;
            } else if (type == typeof(double[]) || type == typeof(Double[])) {
                return false;
            } else if (type == typeof(char[]) || type == typeof(Char[])) {
                return false;
            } else if (type == typeof(byte[]) || type == typeof(Byte[])) {
                return false;
            } else if (type == typeof(void)) {
                return true;
            } else if (type == typeof(bool) || type == typeof(Boolean)) {
                return true;
            } else if (type == typeof(String) || type == typeof(string)) {
                return false;
            } else {
                throw new Exception("unexpected type: " + type);
            }
        }

        public static string GetTypeString(Type type) {
            string typeName;
            if(type == typeof(int) || type == typeof(Int32)) {
                typeName = "int";
            } else if (type == typeof(uint) || type == typeof(UInt32)) {
                typeName = "unsigned int";
            } else if (type == typeof(short) || type == typeof(Int16)) {
                typeName = "short";
            } else if (type == typeof(ushort) || type == typeof(UInt16)) {
                typeName = "unsigned short";
            } else if (type == typeof(long) || type == typeof(Int64)) {
                typeName = "long int";
            } else if (type == typeof(ulong) || type == typeof(UInt64)) {
                typeName = "unsigned long int";
            } else if (type == typeof(float) || type == typeof(Single)) {
                typeName = "float";
            } else if(type == typeof(double) || type == typeof(Double)) {
                typeName = "double";
            } else if(type == typeof(char) || type == typeof(Char) || type == typeof(byte) || type == typeof(Byte)) {
                typeName = "char";
            } else if(type == typeof(int[]) || type == typeof(Int32[])) {
                typeName = "int_array";
            } else if (type == typeof(uint[]) || type == typeof(UInt32[])) {
                typeName = "unsigned_int_array";
            } else if (type == typeof(short[]) || type == typeof(Int16[])) {
                typeName = "short_array";
            } else if (type == typeof(ushort[]) || type == typeof(UInt16[])) {
                typeName = "unsigned_short_array";
            } else if (type == typeof(long[]) || type == typeof(Int64[])) {
                typeName = "long_int_array";
            } else if (type == typeof(ulong[]) || type == typeof(UInt64[])) {
                typeName = "unsigned_long_int_array";
            } else if (type == typeof(float[]) || type == typeof(Single[])) {
                typeName = "float_array";
            } else if (type == typeof(double[]) || type == typeof(Double[])) {
                typeName = "double_array";
            } else if (type == typeof(char[]) || type == typeof(Char[]) || type == typeof(byte[]) || type == typeof(Byte[])) {
                typeName = "char_array";
            } else if(type == typeof(void)) {
                typeName = "void";
            } else if (type == typeof(bool) || type == typeof(Boolean)) {
                typeName = "int";
            } else if (type == typeof(String) || type == typeof(string)) {
                typeName = "char*";
            } else {
                throw new Exception("unexpected type: " + type);
            }
            return typeName;
        }

        public void EmitDeclaration(StringBuilder builder) {
            builder.Append(GetTypeString(Type));
            if(IsPointer)
            {
                builder.Append("*");
            }
            /*if(!IsPrimitive)
            {
                builder.Append("*");
            }*/
            builder.Append(" ");
            builder.Append(Name);
        }

        public void Emit(StringBuilder builder) {
            builder.Append(Name);
        }
    }
}